package geerpc

import (
	"encoding/json"
	"fmt"
	"gitee.com/bankarian/gee-rpc/codec"
	"io"
	"log"
	"net"
	"reflect"
	"sync"
)

// RPC Server
type Server struct{}

func NewServer() *Server {
	return &Server{}
}

// default server instance
var DefaultServer = NewServer()

func (s *Server) Accept(listener net.Listener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println("rpc server: accept error: ", err)
			return
		}
		go s.ServeConn(conn)
	}
}

func Accept(listener net.Listener) {
	DefaultServer.Accept(listener)
}

// ServeConn runs the server on a single connection,
// ServeConn blocks, keep serving the connection until the client hangs up
func (s *Server) ServeConn(conn io.ReadWriteCloser) {
	// 总体上就是干两件事情，读取数据、发送数据
	// 其中读取数据分为，读取 Option，读取 request、body
	defer func() {
		_ = conn.Close()
	}()

	// read option first
	var opt codec.Option
	if err := json.NewDecoder(conn).Decode(&opt); err != nil {
		log.Println("rpc server: options error: ", err)
		return
	}
	if opt.MagicNumber != codec.MagicNumber {
		log.Printf("rpc server: invalid magic number %x", opt.MagicNumber)
		return
	}
	newCodec, ok := codec.NewCodecFuncMap[opt.CodecType]
	if !ok {
		log.Printf("rpc server； invalid codec type %s", opt.CodecType)
		return
	}

	// codec read header and body
	s.serveCodec(newCodec(conn))
}

var invalidRequest = struct {}{}

func (s *Server) serveCodec(cc codec.Codec) {
	sending := new(sync.Mutex) // guarantee complete response
	wg := new(sync.WaitGroup)  // wait until all requests are handled
	for {
		req, err := s.readRequest(cc)
		if err != nil {
			if req == nil {
				break
			}
			req.h.Error = err.Error()
			s.sendResponse(cc, req.h, invalidRequest, sending)
			continue
		}
		wg.Add(1)
		go s.handleRequest(cc, req, sending, wg)
	}
	wg.Wait()
	defer func() {
		_ = cc.Close()
	}()
}

// all infomation of a call
type request struct {
	h       *codec.Header
	argv    reflect.Value
	repleyv reflect.Value
}

func (s *Server) readRequestHeader(cc codec.Codec) (*codec.Header, error) {
	var h codec.Header
	if err := cc.ReadHeader(&h); err != nil {
		if err != io.EOF && err != io.ErrUnexpectedEOF {
			log.Println("rpc server: read header error: ", err)
		}
		return nil, err
	}
	return &h, nil
}

func (s *Server) readRequest(cc codec.Codec) (*request, error) {
	h, err := s.readRequestHeader(cc)
	if err != nil {
		return nil, err
	}
	req := &request{h: h}

	// suppose it's just string
	req.argv = reflect.New(reflect.TypeOf(""))
	if err = cc.ReadBody(req.argv.Interface()); err != nil {
		log.Println("rpc server: read argv err: ", err)
	}
	return req, nil
}

func (s *Server) handleRequest(
	cc codec.Codec,
	req *request,
	sending *sync.Mutex,
	wg *sync.WaitGroup,
) {
	// just print argv and send a "hello" for test
	defer wg.Done()
	log.Println(req.h, req.argv.Elem())
	req.repleyv = reflect.ValueOf(fmt.Sprintf("Hello resp %d", req.h.Seq))
	s.sendResponse(cc, req.h, req.repleyv.Interface(), sending)
}

func (s *Server) sendResponse(
	cc codec.Codec,
	h *codec.Header,
	body interface{},
	sending *sync.Mutex,
) {
	sending.Lock()
	defer sending.Unlock()
	if err := cc.Write(h, body); err != nil {
		log.Println("rpc server: write response error: ", err)
	}
}
